package com.ai.module.chat.config.properties;


import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
import java.util.Map;
import java.util.UUID;


@Configuration
@ConfigurationProperties(prefix="pay.wechat") //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
@Slf4j
public class WxPayConfig {

    // 商户号
    private String mchId;

    private String payCallbackUrl;

    // 商户API证书序列号
    private String mchSerialNo;

    // 商户私钥文件
    private String privateKeyPath;

    // APIv3密钥
    private String apiV3Key;

    // APPID
    private String appId;

    // 微信服务器地址，这个字段没有在，本文中使用到可以不用管
    private String domain=
            "https://api.mch.weixin.qq.com";




    /**
     * 获取商户的私钥文件
     * @param filename
     * @return
     */
    private PrivateKey getPrivateKey(String filename){

        try {
            String realUrl = filename.replaceAll("classpath:", "");
            ClassPathResource resource = new ClassPathResource(realUrl);
            InputStream inputStream = resource.getInputStream();
            return PemUtil.loadPrivateKey(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("私钥文件不存在",e);
            //throw new RuntimeException("私钥文件不存在", e);
            return null;
        }
    }
    //@Bean
    public ClientHttpRequestFactory httpRequestFactory() throws Exception {
        return new HttpComponentsClientHttpRequestFactory(wxPayClient(verifier()));
    }
    @Bean("weChatRestTemplate")
    public RestTemplate weChatRestTemplate(){
        try {
            return new RestTemplate(httpRequestFactory());
        }catch (Exception e){
            log.error("解析错误");
            e.printStackTrace();
            return new RestTemplate();
        }

    }

    /**
     * 获取签名验证器
     * @return
     */
    @Bean
    public Verifier verifier() throws Exception {
        log.info("获取签名验证器");
        //获取商户私钥
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
        // 私钥签名对象
        PrivateKeySigner keySigner = new PrivateKeySigner(mchSerialNo, privateKey);
        // 身份认证对象
        WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, keySigner);

        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(mchId, wechatPay2Credentials,
                apiV3Key.getBytes(StandardCharsets.UTF_8));
        // ... 若有多个商户号，可继续调用putMerchant添加商户信息
        Verifier verifier = certificatesManager.getVerifier(mchId);

        return verifier;
    }

    /**
     * 获取http请求对象
     * @param verifier
     * @return
     */
    @Bean("wxPayClient")
    public HttpClient wxPayClient(Verifier verifier){

        log.info("获取httpclient");

        //获取商户私钥
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
        // 从证书管理器中获取verifier
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, mchSerialNo, privateKey)
                .withValidator(new WechatPay2Validator(verifier));
        // ... 接下来，你仍然可以通过builder设置各种参数，来配置你的HttpClient

        // 通过WechatPayHttpClientBuilder构造的HttpClient，会自动的处理签名和验签，并进行证书自动更新
        CloseableHttpClient httpClient = builder

                .build();

        return httpClient;
    }

    /**
     * 获取HttpClient，无需进行应答签名验证，跳过验签的流程
     */
    @Bean(name = "wxPayNoSignClient")
    public CloseableHttpClient getWxPayNoSignClient(){

        //获取商户私钥
        PrivateKey privateKey = getPrivateKey(privateKeyPath);

        //用于构造HttpClient
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                //设置商户信息
                .withMerchant(mchId, mchSerialNo, privateKey)
                //无需进行签名验证、通过withValidator((response) -> true)实现
                .withValidator((response) -> true);

        // 通过WechatPayHttpClientBuilder构造的HttpClient，会自动的处理签名和验签，并进行证书自动更新
        CloseableHttpClient httpClient = builder.build();

        log.info("== getWxPayNoSignClient END ==");
        return httpClient;
    }

    public String decryptFromResource(Map<String,Object> bodyMap) throws GeneralSecurityException {
        log.info("秘文解密");

        //通知数据
        Map<String,String > resourceMap =(Map<String, String>) bodyMap.get("resource");
        //数据秘文
        String ciphertext = resourceMap.get("ciphertext");
        //获取随机串
        String nonce = resourceMap.get("nonce");
        String associated_data = resourceMap.get("associated_data");

        log.info("秘文===》{}",ciphertext);
        AesUtil aesUtil = new AesUtil(getApiV3Key().getBytes(StandardCharsets.UTF_8));
        //获取明文(解密后的数据)
        String plainText = aesUtil.decryptToString(associated_data.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                ciphertext);

        log.info("明文====》{}",plainText);

        return plainText;
    }


    /**
     * 拼接五个参数
     * @param appId
     * @param timestamp
     * @param nonceStr
     * @param packag
     * @return
     */
    public  String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packag + "\n";
    }

    /**
     * 进行二次封装
     * @param wxCertPath
     * @param message
     * @return
     * @throws NoSuchAlgorithmException
     * @throws SignatureException
     * @throws IOException
     * @throws InvalidKeyException
     * @throws java.security.InvalidKeyException
     */
    public  String sign(String wxCertPath,byte[] message) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException, java.security.InvalidKeyException {
        Signature sign = Signature.getInstance("SHA256withRSA"); //SHA256withRSA
        sign.initSign(PemUtil.loadPrivateKey(new FileInputStream(wxCertPath))); // 微信证书私钥
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }
    /**
     * 获取32位随机字符串
     * @return
     */
    public  String getNonceStr(){
        return UUID.randomUUID().toString()
                .replaceAll("-", "")
                .substring(0, 32);
    }
    /**
     * 获取当前时间戳，单位秒
     * @return
     */
    public long getCurrentTimestamp() {
        return System.currentTimeMillis()/1000;
    }

    /**
     * 作用：使用字段appId、timeStamp、nonceStr、package计算得出的签名值
     * 场景：根据微信统一下单接口返回的 prepay_id 生成调启支付所需的签名值
     * @param timestamp
     * @param nonceStr
     * @param pack package
     * @return
     * @throws Exception
     */
    public String getSign( long timestamp,
                           String nonceStr,
                           String pack) throws Exception{
        String message = buildMessage(appId, timestamp, nonceStr, pack);
        String paySign= sign(message.getBytes("utf-8"));
        return paySign;
    }

    private String buildMessage(String appId, long timestamp, String nonceStr, String pack) {
        return  String.format("%s\n%s\n%s\n%s\n",appId,timestamp,nonceStr,pack);
//                appId + "\n"
//                + timestamp + "\n"
//                + nonceStr + "\n"
//                + pack + "\n";
    }
    private String sign(byte[] message) throws Exception{
        Signature sign = Signature.getInstance("SHA256withRSA");
        //这里需要一个PrivateKey类型的参数，就是商户的私钥。
        //获取商户私钥
        String realUrl = privateKeyPath.replaceAll("classpath:", "");
        ClassPathResource resource = new ClassPathResource(realUrl);
        InputStream inputStream = resource.getInputStream();
        sign.initSign(PemUtil.loadPrivateKey(inputStream));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

}


